﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace OpGen.Compiler.Generator
{
    /// <summary>
    /// Stellt den Generator dar
    /// </summary>
    public class Generator
    {
        /// <summary>
        /// Startet den Generierung der Ausgabedatei
        /// </summary>
        /// <param name="project"></param>
        /// <param name="codeWriter"></param>
        public static void GenerateCode(ProjectElement project, CodeWriter codeWriter)
        {
            codeWriter.AutoNewLine = !project.CSSmartMode;
            codeWriter.UseBlockSpace = !project.CSSmartMode;

            Logger.Normal("Begin Generate...");

            Logger.Normal("Create Header");
            codeWriter.WriteTitleInfo(project);
            codeWriter.WriteImports(project);

            var useExtensions = project.UseExtension;

            foreach (NamespaceElement topElement in project.ChildElements)
            {
                Logger.Debug("Write Namespace {0}", topElement.Elementname);
                codeWriter.BeginNamespace(topElement);

                foreach (var subElement in topElement.ChildElements)
                {
                    if (subElement.ElementType == ElementTypes.Enum)
                    {
                        Logger.Debug("Write Enum {0}", subElement.Elementname);
                        codeWriter.BeginEnum((EnumElement)subElement);

                        codeWriter.EnumItem((EnumElement)subElement);

                        codeWriter.EndEnum();
                    }

                    if (subElement.ElementType == ElementTypes.Class)
                    {
                        Logger.Debug("Write Class {0}", subElement.Elementname);
                        codeWriter.BeginClass((ClassElement)subElement, useExtensions);

                        foreach (FieldElement Element in subElement.ChildElements)
                        {
                            Logger.Debug("Write Field {0}", Element.Elementname);
                            codeWriter.BeginField(Element);
                            codeWriter.EndField(Element);
                        }

                        Logger.Debug("Write Constructor");
                        codeWriter.Constructor(subElement);

                        foreach (FieldElement element in subElement.ChildElements)
                        {
                            Logger.Debug("Write Property {0}", element.Elementname);
                            codeWriter.BeginProperty(element);
                            codeWriter.GetterProperty(element);
                            codeWriter.SetterProperty(element);
                            codeWriter.EndProperty(element);
                        }

                        Logger.Debug("Write Methods");
                        codeWriter.Methods(subElement, useExtensions);
                        
                        codeWriter.EndClass();
                    }

                    if (subElement.ElementType == ElementTypes.Message)
                    {
                        Logger.Debug("Write Message {0}", subElement.Elementname);
                        codeWriter.BeginMessage((MessageElement)subElement, useExtensions);
                        
                        foreach (FieldElement element in subElement.ChildElements)
                        {
                            Logger.Debug("Write Field {0}", element.Elementname);
                            codeWriter.BeginField(element);
                            codeWriter.EndField(element);
                        }

                        Logger.Debug("Write Constructor");
                        codeWriter.Constructor(subElement);

                        foreach (FieldElement element in subElement.ChildElements)
                        {
                            Logger.Debug("Write Property {0}", element.Elementname);
                            codeWriter.BeginProperty(element);
                            codeWriter.GetterProperty(element);
                            codeWriter.SetterProperty(element);
                            codeWriter.EndProperty(element);
                        }

                        Logger.Debug("Write Methods");

                        codeWriter.Methods(subElement, useExtensions);

                        codeWriter.EndMessage();                    
                    }
                }

                codeWriter.EndNamespace();
            }

            Logger.Normal("...Complet");
        }
    }
}
